/*
 * @Author: xiaosihan
 * @Date: 2021-03-28 02:13:06
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-10-03 11:37:40
 */

import shortid from 'shortid';
import { Modal, Slider } from "antd";
import { cloneDeep, isEmpty, isEqual, pick } from "lodash";
import { Event, EventDispatcher, MeshStandardMaterial, MeshStandardMaterialParameters } from "three";
import commonService from '@/api/services/commonService';
import { AllProperty } from '#/type';

// 全局公共方法
class Utils extends EventDispatcher {
  constructor() {
    super();
  }

  isDev = process.env.NODE_ENV === "development";

  isTest = process.env.NODE_ENV === "test";

  isProd = process.env.NODE_ENV === "production"

  // 生成一个短ID
  uuid() {
    const shortId = shortid();
    return shortId;
  }

  // 设置oss图片的后缀  不传width就表示去掉oss后缀
  ossSuffix(src: string, maxSide?: number) {
    let newSrc = (src || "").replace(/(\?|&)(x-oss-process=.*?)(?=&|$)/, '').replace(/^https?:/, "");
    if (maxSide) {
      newSrc += `?x-oss-process=image/resize,m_lfit,w_${maxSide},h_${maxSide}`;
    }
    return newSrc; //补回https前缀
  }

  // 数字加千分位
  thousand(number: string | number, dot = 0) {
    let strNum = String(Number(Number(number).toFixed(dot))); // 转化成字符串
    while (strNum !== strNum.replace(/(\d)(\d{3})(\.|,|$)/, "$1,$2$3")) {
      strNum = strNum.replace(/(\d)(\d{3})(\.|,|$)/, "$1,$2$3");
    }
    return strNum;
  }

  // 数字转换单位 默认保留2位小数
  numToUnit(num: number, dot = 2) {
    let value = "";
    let unit = "";
    if (Math.abs(num) >= 1000000000000) {
      value = this.thousand(num / 1000000000000, dot);
      unit = "万亿";

    } else if (Math.abs(num) >= 100000000) {
      value = this.thousand(num / 100000000, dot)
      unit = "亿"
    } else if (Math.abs(num) >= 10000) {
      value = this.thousand(num / 10000, dot)
      unit = "万"
    } else {
      value = this.thousand(num, dot)
      unit = ""
    }
    return { value, unit, valueUnit: value + unit };
  }

  // 取随机数在某个范围里
  rand(start: number, end: number) {
    return Math.floor(Math.random() * (end - start + 1) + start);
  }

  // 获取是星期几
  getWeekDay() {
    const d = new Date().getDay();
    const arr = ["天", "一", "二", "三", "四", "五", "六"];
    return arr[d];
  }

  // 获取日期
  getDate(seperator: string = ".") {
    // 获取当前日期
    let date = new Date();

    // 获取当前月份
    let nowMonth = date.getMonth() + 1;

    // 获取当前是几号
    let strDate = date.getDate();


    // 对月份进行处理，1-9月在前面添加一个“0”
    if (nowMonth >= 1 && nowMonth <= 9) {
      nowMonth = "0" + nowMonth as any;
    }

    // 对月份进行处理，1-9号在前面添加一个“0”
    if (strDate >= 0 && strDate <= 9) {
      strDate = "0" + strDate as any;
    }

    // 最后拼接字符串，得到一个格式为(yyyy-MM-dd)的日期
    let nowDate = date.getFullYear() + seperator + nowMonth + seperator + strDate;
    return nowDate;
  }

  // 获取时分秒
  getHourMinuteSecond(seperator: string = ":") {
    let today = new Date();
    let h = today.getHours();
    let m = today.getMinutes();
    let s = today.getSeconds();
    // 在 numbers<10 的数字前加上 0
    m = m < 10 ? "0" + m : m as any;
    s = s < 10 ? "0" + s : s as any;
    return h + seperator + m + seperator + s;
  }

  /**
 * 多选文件
 */
  async selectFiles(accept = ".jpg,.jpeg,.png,.tga,.webp"): Promise<File[]> {
    return new Promise<File[]>((resolve) => {
      const input = document.createElement("input");
      input.style.display = "none";
      input.type = "file";
      input.multiple = true;
      input.accept = accept;
      input.onchange = (e: any) => {
        const files = e.target.files as unknown as Promise<File[]>;
        resolve(files);
      }
      input.oncancel = () => {
        resolve([]);
      }
      document.body.append(input);
      input.click();
      setTimeout(() => {
        input.remove();
      }, 100);
    });
  }

  /**
   * 单选文件
   */
  async selectFile(accept = ".jpg,.jpeg,.png,.tga,.webp"): Promise<File | undefined> {
    return new Promise<File | undefined>((resolve) => {
      const input = document.createElement("input");
      input.style.display = "none";
      input.type = "file";
      input.multiple = false;
      input.accept = accept;
      input.onchange = (e: any) => {
        const files = e.target.files as PromiseLike<File>;
        resolve((files as unknown as File[])[0]);
      }
      input.oncancel = () => {
        resolve(undefined);
      }
      document.body.append(input);
      input.click();
      setTimeout(() => {
        input.remove();
      }, 100);
    });
  }

  /**
   * 多选文件转blob
   */
  async selectFileToBlobs(accept = ".jpg,.jpeg,.png,.tga,.webp"): Promise<string[]> {
    const files = await this.selectFiles(accept);
    return files.map(file => window.URL.createObjectURL(file));
  }

  /**
   * 单选文件转blob
   */
  async selectFileToBlob(accept = ".jpg,.jpeg,.png,.tga,.webp"): Promise<string | undefined> {
    const file = await this.selectFile(accept);
    if (file) {
      return window.URL.createObjectURL(file);
    } else {
      return undefined;
    }
  }

  // 下载文件到本地
  download(url: string, fileName: string = url) {
    const downloadLink = document.createElement('a');
    downloadLink.href = url;
    downloadLink.download = fileName;
    downloadLink.click();
  }

  // 下载url并转为File 对象
  async downloadFile(url: string, fileName: string = url) {
    const res = await fetch(url);
    const blob = await res.blob();
    return new File([blob], fileName, { type: blob.type });
  }


  // 选择颜色
  colorPick = (color: `#${string}`, callback: ((this: GlobalEventHandlers, ev: Event) => any) | null) => {
    const input = document.createElement("input");
    input.type = "color";
    input.value = color;
    input.style.position = "absolute";
    input.style.top = "50%";
    input.style.left = "50%";
    input.style.transform = "translate(-50%, -50%)";
    document.body.append(input);
    input.oninput = callback;
    input.onblur = input.remove;
    input.click();
  }

  // 材质编辑
  materialEditor = (name: string, material: MeshStandardMaterial) => {

    const params: Partial<MeshStandardMaterialParameters> = {
      name,
      color: material.color.getHexString()
    };

    if (material.transparent) {
      Object.assign(params, { opacity: material.opacity });
    }

    if (material.hasOwnProperty("metalness")) {
      Object.assign(params, { metalness: material.metalness });
    }

    if (material.hasOwnProperty("roughness")) {
      Object.assign(params, { roughness: material.roughness });
    }

    Modal.info({
      title: name,
      mask: false,
      content: (() => {

        // 修改参数
        const modifyProp = ({ color, ...parma }: Partial<MeshStandardMaterialParameters>) => {
          if (color) {
            Object.assign(params, { color });
            material.color.set(color);
          }
          Object.assign(params, parma);
          Object.assign(material, parma);
        }

        return (
          <div>
            <span>颜色值 </span><input type="color" defaultValue={`#${material.color.getHexString()}`} onChange={e => modifyProp({ color: e.target.value })} /><br />

            {material.transparent && <>
              <span>透明度</span> <Slider style={{ width: 250, display: "inline-block", verticalAlign: "middle" }} min={0} max={1} step={0.01} defaultValue={material.opacity} onChange={v => modifyProp({ opacity: v })} />
            </>}

            {material.hasOwnProperty("metalness") && <>
              <span>金属性</span> <Slider style={{ width: 250, display: "inline-block", verticalAlign: "middle" }} min={0} max={1} step={0.01} defaultValue={material.metalness} onChange={v => modifyProp({ metalness: v })} />
            </>}

            {material.hasOwnProperty("roughness") && <>
              <span>粗糙度</span> <Slider style={{ width: 250, display: "inline-block", verticalAlign: "middle" }} min={0} max={1} step={0.01} defaultValue={material.roughness} onChange={v => modifyProp({ roughness: v })} />
            </>}

          </div>
        );
      })(),
      okText: "复制参数",
      onOk() {
        navigator.clipboard.writeText(JSON.stringify(params));
      },
    });
  }

  /**
   * 比对指定字段是否相同
   */
  isEqualWidth(obj1: {}, obj2: {}, picks: Array<string> = []) {
    if (isEmpty(picks)) {
      return isEqual(obj1, obj2);
    }
    return isEqual(pick(obj1, picks), pick(obj2, picks));
  }

  // 使用示例  
  // const base64Str = '...';  
  // const fileName = 'example.png';  
  // const file = base64ToFile(base64Str, fileName);  
  base64ToFile(base64: string, fileName: string = `${Math.random()}.png`) {
    let arr = base64.split(",");
    //@ts-ignore
    let mime = arr[0].match(/:(.*?);/)[1];
    let bstr = atob(arr[1]);
    let n = bstr.length;
    let u8arr = new Uint8Array(n);

    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], fileName, { type: mime });

  }

  // 5740
  // 商品的公共配置
  allProperty?: AllProperty;
  getAllPropertying = false
  async getAllProperty(): Promise<AllProperty> {
    if (isEmpty(this.allProperty) && this.getAllPropertying === false) {
      this.getAllPropertying = true;
      try {
        const res = await commonService.getCustomApi('/common/baseProperty/getAllProperty', {});
        this.allProperty = res;
        this.getAllPropertying = false;
      } catch (error) {
        return this.getAllProperty();
      }
    }
    while (isEmpty(this.allProperty)) {
      await new Promise(resolve => requestAnimationFrame(resolve));
    }

    return cloneDeep(this.allProperty);
  }


}

const utils = new Utils();

export default utils;